﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CommonTools.Util
{
    [StructLayout(LayoutKind.Sequential)]
    public struct MEMORY_INFO
    {
        public uint dwLength;
        public uint dwMemoryLoad;//内存占用比
        public UInt64 dwTotalPhys;//物理内存总大小
        public UInt64 dwAvailPhys;//可用物理内存大小
        public UInt64 dwTotalPageFile;//页面文件总大小
        public UInt64 dwAvailPageFile;//可用页面文件大小
        public UInt64 dwTotalVirtual;//返回调用进程的用户模式部分的全部可用虚拟地址空间
        public UInt64 dwAvailVirtual;//返回调用进程的用户模式部分的实际可用虚拟地址空间
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MEMORYSTATUSEX
    {
        public uint dwLength;
        public uint dwMemoryLoad;
        public ulong ullTotalPhys;
        public ulong ullAvailPhys;
        public ulong ullTotalPageFile;
        public ulong ullAvailPageFile;
        public ulong ullTotalVirtual;
        public ulong ullAvailVirtual;
        public ulong ullAvailExtendedVirtual;
    }

    public class MemoryInfo
    {
        public uint memoryLoad { get; set; }
        public ulong totalPhys { get; set; } //以Bite为单位
        public ulong availPhys { get; set; } //以Bite为单位
    }

    [Serializable]
    public class MachineMonitorInfo
    {
        public float CpuUsage { get; set; }
        public int CoreNumber { get; set; }
        public float MemoryAvailable { get; set; }
        public float PhysicalMemory { get; set; }
        public Dictionary<string, float> HardDiskFreeSpaceDic { get; set; } = new Dictionary<string, float>();
        public Dictionary<string, float> HardDiskTotalSpaceDic { get; set; } = new Dictionary<string, float>();

    }

    public class MonitorOption
    {
        public bool CpuRadtioEnabled { get; set; } = true;
        public int CpuRadtioInterval { get; set; } = 1000;
        public bool CpuCountEnabled { get; set; } = false;
        public int CpuCountInterval { get; set; } = 1000;
        public bool MemoryAvaliabledEnabled { get; set; } = true;
        public int MemoryAvaliabledInterval { get; set; } = 1000;
        public bool MemoryTotalEnabled { get; set; } = true;
        public int MemoryTotalInterval { get; set; } = 1000;

        public List<string> DiskList { get; set; }
        public bool DiskEnabled { get; set; } = true;
        public int DiskInterval { get; set; } = 1000;
    }

    public sealed class CPUMonitor
    {
        private static readonly CPUMonitor instance = new CPUMonitor();
        public static CPUMonitor Instance
        {
            get { return instance; }
        }

        private PerformanceCounter pcCpuLoad;
        public CPUMonitor()
        {
            pcCpuLoad = new PerformanceCounter("Processor", "% Processor Time", "_Total");
            pcCpuLoad.MachineName = ".";
            pcCpuLoad.NextValue();
            Thread.Sleep(1000);
        }

        public static float GetValue()
        {
            return instance.pcCpuLoad.NextValue();
        }
    }

    public sealed class ProcessorCountMonitor
    {
        private static readonly ProcessorCountMonitor instance = new ProcessorCountMonitor();
        public static ProcessorCountMonitor Instance
        {
            get { return instance; }
        }

        private int m_ProcessorCount;
        public ProcessorCountMonitor()
        {
            m_ProcessorCount = Environment.ProcessorCount;
        }

        public static int GetValue()
        {
            return instance.m_ProcessorCount;
        }
    }

    public sealed class MemoryMonitor
    {
        /// <summary>
        /// 获取内存信息
        /// </summary>
        /// <param name="meminfo"></param>
        [DllImport("kernel32")]
        private static extern void GlobalMemoryStatus(ref MEMORY_INFO meminfo);
        [DllImport("kernel32")]
        private static extern void GlobalMemoryStatusEx(ref MEMORYSTATUSEX stat);

        /// <summary>
        /// 获取内存信息
        /// </summary>
        /// <returns></returns>
        public static MemoryInfo GetMemoryInfo()
        {
            MEMORY_INFO memInfo = new MEMORY_INFO();
            MEMORYSTATUSEX memEx = new MEMORYSTATUSEX();
            memEx.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
            GlobalMemoryStatusEx(ref memEx);
            GlobalMemoryStatus(ref memInfo);
            MemoryInfo memoryInfo = new MemoryInfo();
            memoryInfo.memoryLoad = memInfo.dwMemoryLoad;
            memoryInfo.availPhys = memInfo.dwAvailPhys;
            memoryInfo.totalPhys = memInfo.dwTotalPhys;
            return memoryInfo;
        }

        /// <summary>
        /// 获取内存占用率
        /// </summary>
        /// <returns></returns>
        public static uint GetMemoryLoad()
        {
            MEMORY_INFO memInfo = new MEMORY_INFO();
            MEMORYSTATUSEX memEx = new MEMORYSTATUSEX();
            memEx.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
            GlobalMemoryStatusEx(ref memEx);
            GlobalMemoryStatus(ref memInfo);
            return memInfo.dwMemoryLoad;
        }

        /// <summary>
        /// 获取指定驱动器的空间总大小(B)
        /// </summary>
        /// <param name="str_HardDiskName"></param>
        /// <returns></returns>
        public static long GetHardDiskSpace(string str_HardDiskName)
        {
            long totalSize = new long();
            str_HardDiskName = str_HardDiskName + ":\\";
            System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
            foreach (var drive in drives)
            {
                if (drive.Name == str_HardDiskName)
                    totalSize = drive.TotalSize;
            }
            return totalSize;
        }

        /// <summary>
        /// 获取指定驱动器的剩余空间总大小(B)
        /// </summary>
        /// <param name="str_HardDiskName"></param>
        /// <returns></returns>
        public static long GetHardDiskFreeSpace(string str_HardDiskName)
        {
            long freeSpace = new long();
            str_HardDiskName = str_HardDiskName + ":\\";
            System.IO.DriveInfo drive = System.IO.DriveInfo.GetDrives().FirstOrDefault(t => t.Name == str_HardDiskName);
            if (drive != null) freeSpace = drive.TotalFreeSpace;
            return freeSpace;
        }
    }



    public sealed class MonitorHelper
    {
        public static MachineMonitorInfo Info = new MachineMonitorInfo();

        public static void GetMachineMonitorInfo(MonitorOption option)
        {
            try
            {
                if (option.CpuRadtioEnabled)
                    Task.Run(() => GetCpuRadtio(option.CpuRadtioInterval)).LogExceptions("获取CPU占用比");
                if (option.CpuCountEnabled)
                    Task.Run(() => GetCpuCount(option.CpuCountInterval)).LogExceptions("获取CPU核数");
                if (option.MemoryAvaliabledEnabled)
                    Task.Run(() => GetCpuMemoryAvaliabled(option.MemoryAvaliabledInterval)).LogExceptions("获取可用内存");
                if (option.MemoryTotalEnabled)
                    Task.Run(() => GetMemoryTotal(option.MemoryTotalInterval)).LogExceptions("获取总内存");
                if (option.DiskList.Count > 0 && option.DiskEnabled)
                    Task.Run(() => GetDiskInfo(option.DiskList, option.DiskInterval)).LogExceptions("获取磁盘空间");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private static void GetCpuRadtio(int interval)
        {
            while (true)
            {
                Thread.Sleep(interval);
                lock (Info)
                {
                    Info.CpuUsage = CPUMonitor.GetValue();
                }
            }
        }

        private static void GetCpuCount(int interval)
        {
            while (true)
            {
                Thread.Sleep(interval);
                lock (Info)
                {
                    Info.CoreNumber = ProcessorCountMonitor.GetValue();
                }
            }
        }

        private static void GetCpuMemoryAvaliabled(int interval)
        {
            while (true)
            {
                Thread.Sleep(interval);
                lock (Info)
                {
                    Info.MemoryAvailable = (float)(MemoryMonitor.GetMemoryInfo().availPhys / 1024.0 / 1024.0 / 1024.0);
                }
            }
        }

        private static void GetMemoryTotal(int interval)
        {
            while(true)
            {
                Thread.Sleep(interval);
                lock(Info)
                {
                    Info.PhysicalMemory = (float)(MemoryMonitor.GetMemoryInfo().totalPhys / 1024.0 / 1024.0 / 1024.0);
                }
            }
        }

        private static void GetDiskInfo(List<string> list, int interval)
        {
            while(true)
            {
                Thread.Sleep(interval);
                lock(Info)
                {
                    foreach (var item in list)
                    {
                        try
                        {
                            if (Info.HardDiskFreeSpaceDic.ContainsKey(item))
                                Info.HardDiskFreeSpaceDic[item] = (float)(MemoryMonitor.GetHardDiskFreeSpace(item) / 1024.0 / 1024.0 / 1024.0);
                            else
                                Info.HardDiskFreeSpaceDic.Add(item, (float)(MemoryMonitor.GetHardDiskFreeSpace(item) / 1024.0 / 1024.0 / 1024.0));

                            if (Info.HardDiskTotalSpaceDic.ContainsKey(item))
                                Info.HardDiskTotalSpaceDic[item] = (float)(MemoryMonitor.GetHardDiskSpace(item) / 1024.0 / 1024.0 / 1024.0);
                            else
                                Info.HardDiskTotalSpaceDic.Add(item, (float)(MemoryMonitor.GetHardDiskSpace(item) / 1024.0 / 1024.0 / 1024.0));
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex);
                        }
                    }
                }
            }
        }


    }
}
